﻿#include <iostream>
#include <cstring>
#include <ctime>
#include <sys/socket.h>
#include <netinet/ip_icmp.h>
#include <netinet/in.h>
#include <unistd.h>
#include <arpa/inet.h>

#define BUFFER_SIZE 1024

// 计算校验和
unsigned short calculate_checksum(void *b, int len) {
    unsigned short *buf = (unsigned short *)b;
    unsigned int sum = 0;
    unsigned short result;

    for (sum = 0; len > 1; len -= 2)
        sum += *buf++;
    if (len == 1)
        sum += *(unsigned char *)buf;
    sum = (sum >> 16) + (sum & 0xFFFF);
    sum += (sum >> 16);
    result = ~sum;
    return result;
}

int main() {
    int sockfd = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
    if (sockfd < 0) {
        perror("Socket creation failed");
        return 1;
    }

    char buffer[BUFFER_SIZE];
    struct sockaddr_in client_addr;
    socklen_t addr_len = sizeof(client_addr);

    while (true) {
        memset(buffer, 0, BUFFER_SIZE);
        ssize_t bytes_received = recvfrom(sockfd, buffer, BUFFER_SIZE, 0, (struct sockaddr *)&client_addr, &addr_len);
        if (bytes_received <= 0) {
            perror("Failed to receive data");
            continue;
        }

        struct icmphdr *icmp_hdr = (struct icmphdr *)(buffer + sizeof(struct iphdr));
        if (icmp_hdr->type == ICMP_ECHO) {
            std::cout << "Received ICMP Echo Request" << std::endl;

            // 构造ICMP Echo Reply
            char reply[BUFFER_SIZE];
            memset(reply, 0, BUFFER_SIZE);
            struct icmphdr *reply_hdr = (struct icmphdr *)reply;
            reply_hdr->type = ICMP_ECHOREPLY;
            reply_hdr->code = 0;
            reply_hdr->un.echo.id = icmp_hdr->un.echo.id;
            reply_hdr->un.echo.sequence = icmp_hdr->un.echo.sequence;

            // 添加时间戳
            time_t now = time(nullptr);
            memcpy(reply + sizeof(struct icmphdr), &now, sizeof(now));

            reply_hdr->checksum = 0;
            reply_hdr->checksum = calculate_checksum(reply, sizeof(struct icmphdr) + sizeof(now));

            ssize_t bytes_sent = sendto(sockfd, reply, sizeof(struct icmphdr) + sizeof(now), 0,
                                        (struct sockaddr *)&client_addr, addr_len);
            if (bytes_sent <= 0) {
                perror("Failed to send reply");
            } else {
                std::cout << "Sent ICMP Echo Reply with timestamp" << std::endl;
            }
        }
    }

    close(sockfd);
    return 0;
}

